package com.yyr.callmessage.core.util;


import com.google.common.base.Splitter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class TimeUtil {

    //线程安全
    private static final DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyyMMddHHmmss", Locale.CHINA);
    private static final DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
    private static final DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyyMMdd", Locale.CHINA);
    private static final DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.CHINA);
    private static final ZoneId chinaZone = ZoneId.of("Asia/Shanghai");
    private static final ZoneOffset chineZoneOffset = ZoneOffset.of("+8");

    /**
     * 获取本月开始时
     *
     * @return
     */
    public static Long getFirstTimeByMonth() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        //将小时至0
        c.set(Calendar.HOUR_OF_DAY, 0);
        //将分钟至0
        c.set(Calendar.MINUTE, 0);
        //将秒至0
        c.set(Calendar.SECOND, 0);
        //将毫秒至0
        c.set(Calendar.MILLISECOND, 0);
        return c.getTimeInMillis();
    }

    /**
     * 获取本月结束时
     *
     * @return
     */
    public static Long getLastTimeByMonth() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.MONTH, 0);
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        int lastMonthMaxDay = ca.getActualMaximum(Calendar.DAY_OF_MONTH);
        ca.set(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH), lastMonthMaxDay, 23, 59, 59);
        return ca.getTimeInMillis();
    }

    /**
     * 获取上个月开始时
     *
     * @return
     */
    public static Long getFirstTimeByLastMonth() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, -1);
        c.set(Calendar.DAY_OF_MONTH, 1);
        //将小时至0
        c.set(Calendar.HOUR_OF_DAY, 0);
        //将分钟至0
        c.set(Calendar.MINUTE, 0);
        //将秒至0
        c.set(Calendar.SECOND, 0);
        //将毫秒至0
        c.set(Calendar.MILLISECOND, 0);
        return c.getTimeInMillis();
    }

    /**
     * 获取上个月结束时
     *
     * @return
     */
    public static Long getLastTimeByLastMonth() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.MONTH, -1);
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        int lastMonthMaxDay = ca.getActualMaximum(Calendar.DAY_OF_MONTH);
        ca.set(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH), lastMonthMaxDay, 23, 59, 59);
        return ca.getTimeInMillis();
    }

    //获取当天开始时
    public static Long getFirstTimeByToday() {
        Calendar todayStart = Calendar.getInstance();
        todayStart.set(Calendar.HOUR_OF_DAY, 0);
        todayStart.set(Calendar.MINUTE, 0);
        todayStart.set(Calendar.SECOND, 0);
        todayStart.set(Calendar.MILLISECOND, 0);
        return todayStart.getTimeInMillis();
    }

    //获取当天结束时
    public static Long getLastTimeByToday() {
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.set(Calendar.HOUR_OF_DAY, 23);
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        return todayEnd.getTimeInMillis();
    }

    //获取上一天开始时
    public static Long getFirstTimeByLastDay() {
        Calendar todayStart = Calendar.getInstance();
        todayStart.add(Calendar.DAY_OF_MONTH, -1);
        todayStart.set(Calendar.HOUR_OF_DAY, 0);
        todayStart.set(Calendar.MINUTE, 0);
        todayStart.set(Calendar.SECOND, 0);
        todayStart.set(Calendar.MILLISECOND, 0);
        return todayStart.getTimeInMillis();
    }

    //获取上一天结束时
    public static Long getLastTimeByLastDay() {
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.add(Calendar.DAY_OF_MONTH, -1);
        todayEnd.set(Calendar.HOUR_OF_DAY, 23);
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        return todayEnd.getTimeInMillis();
    }

    //获取明天开始时
    public static Long getFirstTimeByNextDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    //获取下个月开始时
    public static Long getFirstTimeByNextMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1); //设置为下个月1号
        //将小时至0
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        //将分钟至0
        calendar.set(Calendar.MINUTE, 0);
        //将秒至0
        calendar.set(Calendar.SECOND, 0);
        //将毫秒至0
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    //获取当前时间的下一天的0点0分0秒
    public static Long getNextHour() {
        return getTimeByZero(System.currentTimeMillis(), 1);
    }

    //获取当前时间的下分钟
    public static Long getNextMinutes() {
        Calendar calendar = Calendar.getInstance();
        int minute = calendar.get(Calendar.MINUTE);
        calendar.set(Calendar.MINUTE, minute + 1);
        return calendar.getTimeInMillis();
    }

    // 获取时间+几个月
    public static Long getTimeByMonth(long time, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(time);
        calendar.add(Calendar.MONTH, month);
        return calendar.getTimeInMillis();
    }

    //获取时间+几天的0点0分0秒
    public static Long getTimeByZero(long time, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(time);
        //将小时至加1
        calendar.add(Calendar.HOUR_OF_DAY, day);
        //将分钟至0
        calendar.set(Calendar.MINUTE, 0);
        //将秒至0
        calendar.set(Calendar.SECOND, 0);
        //将毫秒至0
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    // yyyyMMddHHmmss
    public static Long getTimestamp1(String time) {
        return LocalDateTime.parse(time, formatter1).toInstant(chineZoneOffset).toEpochMilli();
    }

    // yyyy-MM-dd HH:mm:ss
    public static Long getTimestamp2(String time) {
        return LocalDateTime.parse(time, formatter2).toInstant(chineZoneOffset).toEpochMilli();
    }

    // yyyyMMddHHmmss
    public static String getTimeStr1(long timestamp) {
        return formatter1.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), chinaZone));
    }

    // yyyy-MM-dd HH:mm:ss
    public static String getTimeStr2(long timestamp) {
        return formatter2.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), chinaZone));
    }

    // yyyyMMdd
    public static String getDateStr1(long timestamp) {
        return formatter3.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), chinaZone));
    }

    // yyyy-MM-dd
    public static String getDateStr2(long timestamp) {
        return formatter4.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), chinaZone));
    }

    public static Integer getTodayWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        return cal.get(Calendar.DAY_OF_WEEK) - 1;
    }

    /**
     * 获取指定时间
     *
     * @param hour
     * @param minute
     * @param second
     * @param milliSecond
     * @return
     */
    public static final Long getAppointTime(int hour, int minute, int second, int milliSecond) {
        Calendar calendar = Calendar.getInstance();
//        todayEnd.add(Calendar.DAY_OF_MONTH,0);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, milliSecond);
        Long time = calendar.getTimeInMillis();

        return time;
    }

    /**
     * 把时长转成时间戳,比如5小时3分，1天5小时
     *
     * @param time
     * @return
     */
    public static Long getTimestamp3(String time) {
        StringBuilder formatStr = new StringBuilder();
        boolean isDay = false;
        for (int i = 0; i < time.length(); ++i) {
            char s = time.charAt(i);
            if (s == '天') {
                formatStr.append("D天");
                isDay = true;
            } else if (s == '时') {
                //解决这个输入"12时2分";
                if ('小' == time.charAt(i - 1)) {
                    formatStr.append("k小时");
                } else {
                    formatStr.append("k时");
                }
            } else if (s == '分') {
                formatStr.append("m分");
            } else if (s == '秒') {
                formatStr.append("s秒");
            }
        }
        long timestamp = 0;
        try {
            DateFormat dateFormat = new SimpleDateFormat(formatStr.toString());
            Date date = dateFormat.parse(time);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            int days = calendar.get(Calendar.DAY_OF_YEAR);
            // 判断isDay的意义，是时间戳是从1970.01.01开始算， 如果分割的字符串没有包含天，他这里会是1天
            if (isDay && days > 0) {
                timestamp += days * 86400;
            }
            int hours = calendar.get(Calendar.HOUR_OF_DAY);
            if (hours > 0) {
                timestamp += hours * 3600;
            }
            int minutes = calendar.get(Calendar.MINUTE);
            if (minutes > 0) {
                timestamp += minutes * 60;
            }
            int seconds = calendar.get(Calendar.SECOND);
            if (seconds > 0) {
                timestamp += seconds;
            }
        } catch (Exception err) {
            err.printStackTrace();
        }
        return timestamp * 1000;
    }

    public static boolean isBetweenHour(String timeStr) {
        List<String> forms = Splitter.on("-").omitEmptyStrings().splitToList(timeStr);
        String [] start = forms.get(0).split(":");
        String [] end = forms.get(1).split(":");
        Long startTime = getAppointTime(Integer.valueOf(start[0]), Integer.valueOf(start[1]), 0,0);
        Long endTime = getAppointTime(Integer.valueOf(end[0]), Integer.valueOf(end[1]), 0,0);
        Long nowTime = System.currentTimeMillis();
        if (nowTime < startTime || nowTime > endTime) {
            return false;
        }
        return true;
    }

    /**
     * 获取前n天的时间
     * @param day
     * @return
     */
    public static Long getTimeByDay(int day) {
        Calendar instance = Calendar.getInstance();
        instance.setTimeInMillis(getFirstTimeByNextDay());
        instance.add(Calendar.DATE, day);
        return instance.getTimeInMillis();
    }

    /**
     * 计算起始和结束时间(必须为当天起始时间戳)内包含的天数有几天
     * @param startTime
     * @param endTime
     * @return
     */
    public static int calculateDays(Long startTime, Long endTime) {
        return Math.toIntExact((endTime - startTime) / (86400000L) + 1);
    }

    /**
     * 时间戳转日期字符串
     * @param time 时间戳
     * @param format 时间格式
     * @return 日期字符串
     */
    public static String convertTimeToString(Long time, String format) {
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern(format);
        return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
    }

    /**
     * 根据自定义时间段初始化集合
     * @param startTime
     * @param endTime
     * @return
     */
    public static List<String> getInitializeListByDays(Long startTime, Long endTime) {
        int days = calculateDays(startTime, endTime);
        List<String> list = new ArrayList<>();
        String format = "yyyy-MM-dd";
        Long time = startTime;
        for (int i = 0; i < days; i++) {
            //解析时间格式
            String date = convertTimeToString(time, format);
            list.add(date);
            time = time + 86400000L;
        }
        return list;
    }
}